<?php
namespace PsiFramework\Classes\Util;

import("Classes.Util.Plugin");
import("Classes.Util.Log.Logger");

use \PsiFramework\Classes\Util\Plugin;
use \PsiFramework\Classes\Util\Log\Logger;
use \PsiFramework\Classes\Util\Parameters\Action\ActionMapping;
use \PsiFramework\Classes\Util\Parameters\ObjectParameters;
use \PsiFramework\Classes\Util\Parameters\Parameters;
use \PsiFramework\Classes\Util\UI\Module;
use \PsiFramework\Classes\Util\UI\Response;
use \PsiFramework\Classes\Util\UI\LanguageManager;
use \PsiFramework\Classes\Util\UI\TemplateManager;

/**
 * PsiFramework
 * Php Simple Framework
 *
 * @author Rémi San
 * @version beta
 */

/**
 * The Application class describes an Application
 *
 * @package Model
 */
class Application
{

    public /*bool*/ $insertAppParameter = true ;

    protected /*string*/             $_name ;
    protected /*Application*/        $_parent ;
    protected /*string*/             $_defaultAction ;
    protected /*string*/             $_defaultLanguage ;
    protected /*string*/             $_contact ;
    protected /*Plugin[]*/           $_plugins;
    protected /*ActionMapping*/      $_actionMapping;
    protected /*array*/              $_serviceMapping;
    protected /*ObjectParameters[]*/ $_objectParameters;
    protected /*Module[]*/           $_modules;
    protected /*Parameters*/         $_parameters;
    protected /*bool*/               $_securityCheck;

    protected /*Logger*/             $_logger;

    /**
     *
     * @param string $name
     * @param Application $parent
     * @param string $defaultAction
     * @param string $defaultLanguage
     * @param string $contact
     * @param Plugin[] $plugins
     * @param ActionMapping $actionMapping
     * @param ServiceMapping $serviceMapping
     * @param ObjectParameters[] $objectParameters
     * @param Module[] $modules
     * @param Parameters $parameters
     * @param bool $securityCheck;
     */
    public function __construct(
        /*string*/             $name=null,
        Application            $parent=null,
        /*string*/             $defaultAction=null,
        /*string*/             $defaultLanguage=null,
        /*string*/             $contact=null,
        /*Plugin[]*/           $plugins=null,
        ActionMapping          $actionMapping=null,
        /*array*/              $serviceMapping=null,
        /*ObjectParameters[]*/ $objectParameters=null,
        /*Module[]*/           $modules=null,
        Parameters             $parameters=null,
        /*bool*/               $securityCheck=true
     )
    {
        $this->_name = $name ;
        $this->_parent = $parent ;
        $this->_defaultAction = $defaultAction ;
        $this->_defaultLanguage = $defaultLanguage ;
        $this->_contact = $contact ;
        $this->_plugins = $plugins ;
        $this->_actionMapping = $actionMapping ;
        $this->_serviceMapping = $serviceMapping ;
        $this->_objectParameters = $objectParameters ;
        $this->_modules = $modules ;
        $this->_parameters = $parameters ;
        $this->_securityCheck = $securityCheck ;

        $this->_logger = new Logger("Application");
    }

    public function addObjectParameter(ObjectParameters $objectParameter)
    {
        $this->_logger->debug(
            "Adding '".$objectParameter->getName().
            "' to application '".$this->_name."'"
        );
        
        $this->_objectParameters[
            $objectParameter->getName()
        ] = $objectParameter ;
        
        ObjectParametersDAO::$objectParameters[
            $objectParameter->getName()
        ] = $objectParameter ;
    }

    public function getName()
    {
        return $this->_name ;
    }

    public function getParent()
    {
        return $this->_parent ;
    }

    public function getDefaultActionName()
    {
        return $this->_defaultAction ;
    }

    public function getDefaultAction()
    {
        return $this->getAction($this->_defaultAction);
    }

    public function getDefaultLanguage()
    {
        return $this->_defaultLanguage ;
    }

    public function getContact()
    {
        return $this->_contact ;
    }

    public function getModules()
    {
        return $this->_modules ;
    }

    public function getPlugins()
    {
        return $this->_plugins ;
    }

    public function getActionMapping()
    {
        return $this->_actionMapping ;
    }

    public function getServiceMapping()
    {
        return $this->_serviceMapping ;
    }

    public function getObjectParameters()
    {
        return $this->_objectParameters ;
    }

    public function getParameters()
    {
        return $this->_parameters ;
    }

    public function securityCheck()
    {
        return $this->_securityCheck ;
    }

    public function setName(/*string*/ $name)
    {
        return $this->_name = $name ;
    }

    public function setParent(Application $parent=null)
    {
        return $this->_parent = $parent ;
    }

    public function setDefaultAction(/*string*/ $defaultAction)
    {
        return $this->_defaultAction = $defaultAction ;
    }

    public function setDefaultLanguage(/*string*/ $defaultLanguage)
    {
        return $this->_defaultLanguage = $defaultLanguage ;
    }

    public function setContact(/*string*/ $contact)
    {
        return $this->_contact = $contact ;
    }

    public function setModules(/*array*/ $modules)
    {
        return $this->_modules = $modules ;
    }

    public function setPlugins(/*array*/ $plugins)
    {
        return $this->_plugins = $plugins ;
    }

    public function setActionMapping(ActionMapping $actionMapping=null)
    {
        return $this->_actionMapping = $actionMapping ;
    }

    public function setServiceMapping(/*array*/ $serviceMapping)
    {
        return $this->_serviceMapping = $serviceMapping ;
    }

    public function setObjectParameters(/*array*/ $objectParameters)
    {
        return $this->_objectParameters = $objectParameters ;
    }

    public function setParameters(Parameters $parameters=null)
    {
        return $this->_parameters = $parameters ;
    }

    public function setSecurityCheck(/*bool*/ $securityCheck)
    {
        return $this->_securityCheck = $securityCheck ;
    }
	
    /**
     * 
     * @param unknown_type $moduleName
     * @return \PsiFramework\Classes\Util\UI\Module
     */
    public function getModule(/*string*/ $moduleName)
    {
        $module = null ;

        if (!is_null($this->_modules)
            && array_key_exists($moduleName, $this->_modules)
        ) {
            $module = $this->_modules[$moduleName] ;
        }

        if (is_null($module) && !is_null($this->_parent)) {
            $module = $this->_parent->getModule($moduleName);
        }

        return $module ;
    }

    public function getAction(/*string*/ $actionName=null)
    {

        $action = null ;
        if (!is_null($this->_actionMapping)) {
            $action = $this->_actionMapping->getAction($actionName);
        }

        if (is_null($action) && !is_null($this->_parent)) {
            $action = $this->_parent->getAction($actionName);
        }

        if (is_null($action) && !is_null($this->_plugins)) {
            foreach ($this->_plugins as $plugin) {
                $action = $plugin->getAction($actionName);
                if (!is_null($action)) {
                    break ;
                }
            }
        }

        return $action ;
    }

    public function getServiceClass(/*string*/ $serviceName)
    {
        $serviceClass =null ;

        if (!is_null($this->_serviceMapping)
            && array_key_exists($serviceName, $this->_serviceMapping)
        ) {
            $serviceClass = $this->_serviceMapping[$serviceName] ;
        }

        if (is_null($serviceClass) && !is_null($this->_parent)) {
            $serviceClass = $this->_parent->getServiceClass($serviceName);
        }

        if (is_null($serviceClass) && !is_null($this->_plugins)) {
            foreach ($this->_plugins as $plugin) {
                $serviceClass = $plugin->getServiceClass($serviceName);
                if (!is_null($serviceClass)) {
                    break ;
                }
            }
        }

        return $serviceClass ;
    }

    public function getObjectParameter(/*string*/ $objectName)
    {
        if (isNullOrEmptyString($objectName)) {
            throw new \Exception(
                "Can't retrieve an object with a null name !"
            ); ;
        }

        $objectParameter = null ;
        $this->_logger->debug(
            "Retrieving '".$objectName."' from application '".$this->_name."'"
        );

        if (!is_null($this->_objectParameters)
            && isset($this->_objectParameters[$objectName])
        ) {
            $objectParameter = $this->_objectParameters[$objectName] ;
        }
        if (is_null($objectParameter) && !is_null($this->_parent)) {
            try {
                $objectParameter
                    = $this->_parent->getObjectParameter($objectName);
            }catch (\Exception $e) {
                $objectParameter = null ;
            }
        }
        if (is_null($objectParameter) && !is_null($this->_plugins)) {
            foreach ($this->_plugins as $plugin) {
                try{
                    $objectParameter = $plugin->getObjectParameter($objectName);
                }catch(\Exception $e) {
                    $objectParameter = null ;
                }
                if (!is_null($objectParameter)) {
                    break ;
                }
            }
        }

        if (is_null($objectParameter)) {
            throw new \Exception(
                "The object '".$objectName."' couldn't be retrieved for application !"
            );
        }

        return $objectParameter ;
    }

    public function getParameter(/*string*/ $paramName)
    {
        if (isNullOrEmptyString($paramName)) {
            return null ;
        }

        $param = null ;
        if (!is_null($this->_parameters)) {
            $param = $this->_parameters->getParameter($paramName);
        }

        if (is_null($param) && !is_null($this->_parent)) {
            $param = $this->_parent->getParameter($paramName);
        }
        if (is_null($param) && !is_null($this->_plugins)) {
            foreach ($this->_plugins as $plugin) {
                $param = $plugin->getParameter($paramName);
                if (!is_null($param)) {
                    break ;
                }
            }
        }
        return $param ;
    }

    protected function displayTemplate(
        /*string*/ $template,
        Response   $response=null,
        /*boolean*/ $ajaxCall=false
    )
    {
        $templatePath = $template . '.php' ;
        if (!startsWith($template, '{')) {
            $templatePath = '[' . $this->_name . ']/Template/html/' .
                            $templatePath ;
        }
        $file = getFile($templatePath);
        if (!is_null($file)) {
            $languageManager = LanguageManager::getInstance();
            $templateManager = TemplateManager::getInstance();
            require($file);
        } else {
            if (!is_null($this->_parent)) {
                $this->_parent->displayTemplate($template, $response, $ajaxCall);
            } else {
                throw new \Exception(
                    'Impossible to load template "' . $template . '"'
                );
            }
        }

    }

    public function showTemplate(
        /*string*/  $template,
        Response    $response=null,
        /*boolean*/ $ajaxCall=false
    )
    {

        if (is_null($response)) {
            $response = new Response();
        }
        $response->setAttribute("application", $this);

        $this->displayTemplate($template, $response, $ajaxCall);
    }
}
